/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package com.inspur.edp.lcm.metadata.core;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.inspur.edp.lcm.metadata.api.ConfigData.CommonConfigData;
import com.inspur.edp.lcm.metadata.api.ConfigData.MetadataConfiguration;
import com.inspur.edp.lcm.metadata.api.context.RefCommonContext;
import com.inspur.edp.lcm.metadata.api.entity.GspMetadata;
import com.inspur.edp.lcm.metadata.api.entity.GspProject;
import com.inspur.edp.lcm.metadata.api.entity.Metadata4Ref;
import com.inspur.edp.lcm.metadata.api.entity.Metadata4RefDto;
import com.inspur.edp.lcm.metadata.api.entity.MetadataDto;
import com.inspur.edp.lcm.metadata.api.entity.MetadataFilter;
import com.inspur.edp.lcm.metadata.api.entity.MetadataHeader;
import com.inspur.edp.lcm.metadata.api.entity.MetadataIndexItemDto;
import com.inspur.edp.lcm.metadata.api.entity.MetadataPackage;
import com.inspur.edp.lcm.metadata.api.entity.MetadataPackageHeader;
import com.inspur.edp.lcm.metadata.api.entity.MetadataPackageVersion;
import com.inspur.edp.lcm.metadata.api.entity.MetadataProject;
import com.inspur.edp.lcm.metadata.api.entity.MetadataReference;
import com.inspur.edp.lcm.metadata.api.entity.MetadataType;
import com.inspur.edp.lcm.metadata.api.entity.ProcessMode;
import com.inspur.edp.lcm.metadata.api.entity.ProjectHeader;
import com.inspur.edp.lcm.metadata.api.entity.metadataindex.LocalMetadataIndexItem;
import com.inspur.edp.lcm.metadata.api.entity.metadataindex.MetadataIndexRepoItemDto;
import com.inspur.edp.lcm.metadata.api.mvnEntity.MavenPackageRefs;
import com.inspur.edp.lcm.metadata.api.mvnEntity.MetadataInfoFilter;
import com.inspur.edp.lcm.metadata.api.mvnEntity.MetadataInfoWithVersion;
import com.inspur.edp.lcm.metadata.api.mvnEntity.MetadataMavenInfo;
import com.inspur.edp.lcm.metadata.api.mvnEntity.PackageSourceDto;
import com.inspur.edp.lcm.metadata.api.mvnEntity.PageMetadataInfo;
import com.inspur.edp.lcm.metadata.api.mvnEntity.withprocessmode.MetadataInfoFilterWithProcessMode;
import com.inspur.edp.lcm.metadata.api.mvnEntity.withprocessmode.MetadataInfoWithVersionWithProcessMode;
import com.inspur.edp.lcm.metadata.api.mvnEntity.withprocessmode.MetadataMavenInfoWithProcessMode;
import com.inspur.edp.lcm.metadata.api.mvnEntity.withprocessmode.PageMetadataInfoWithProcessMode;
import com.inspur.edp.lcm.metadata.api.service.MdpkgService;
import com.inspur.edp.lcm.metadata.cache.MetadataDevCacheManager;
import com.inspur.edp.lcm.metadata.common.FileServiceImp;
import com.inspur.edp.lcm.metadata.common.MetadataDtoConverter;
import com.inspur.edp.lcm.metadata.common.MetadataSerializer;
import com.inspur.edp.lcm.metadata.common.Utils;
import com.inspur.edp.lcm.metadata.common.configuration.ContentManagerHelper;
import com.inspur.edp.lcm.metadata.common.configuration.MavenSourceRuleHelper;
import com.inspur.edp.lcm.metadata.common.configuration.MetadataConfigurationHelper;
import com.inspur.edp.lcm.metadata.common.configuration.MetadataTypeHelper;
import com.inspur.edp.lcm.metadata.common.configuration.ReferenceManagerHelper;
import com.inspur.edp.lcm.metadata.core.event.DirEventBroker;
import com.inspur.edp.lcm.metadata.core.event.MetadataCreateEventBroker;
import com.inspur.edp.lcm.metadata.core.event.MetadataEventBroker;
import com.inspur.edp.lcm.metadata.core.manager.IndexServerManager;
import com.inspur.edp.lcm.metadata.core.persistence.RepositoryFactory;
import com.inspur.edp.lcm.metadata.core.refi18n.IRefI18nFilter;
import com.inspur.edp.lcm.metadata.core.refi18n.RefI18nMetadataFactory;
import com.inspur.edp.lcm.metadata.spi.IMetadataReferenceManager;
import com.inspur.edp.lcm.metadata.spi.MetadataContentManager;
import com.inspur.edp.lcm.metadata.spi.event.DirEventArgs;
import com.inspur.edp.lcm.metadata.spi.event.MetadataEventArgs;
import com.inspur.lcm.metadata.logging.LoggerDisruptorQueue;
import io.iec.edp.caf.boot.context.CAFContext;
import io.iec.edp.caf.commons.utils.SpringBeanUtils;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
import org.apache.commons.collections.CollectionUtils;
import org.codehaus.plexus.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author zhaoleitr
 */
public class MetadataCoreManager {
    private static final Logger log = LoggerFactory.getLogger(MetadataCoreManager.class);

    private final FileServiceImp fileService = new FileServiceImp();
    private final MetadataProjectCoreService metadataProjectCoreService = new MetadataProjectCoreService();
    private final GspProjectCoreService gspProjectCoreService = new GspProjectCoreService();
    private final PackageCoreService packageCoreService = new PackageCoreService();
    private final Lock lock = new ReentrantLock();
    private static MetadataCoreManager current;

    public static MetadataCoreManager getCurrent() {
        if (current == null) {
            current = new MetadataCoreManager();
        }
        return current;
    }

    public void initializeMetadataEntity(GspMetadata metadata) {
        metadata.getHeader().setId(UUID.randomUUID().toString());
        MetadataContentManager manager = ContentManagerHelper.getInstance().getManager(metadata.getHeader().getType());
        if (manager != null) {
            manager.build(metadata);
        }
    }

    public void createMetadata(String absolutePath, GspMetadata metadata) {
        // 元数据名称
        String suffix = MetadataTypeHelper.getInstance().getMetadataType(metadata.getHeader().getType()).getPostfix();
        String name = metadata.getHeader().getCode() + suffix;
        String fullPath = fileService.getCombinePath(absolutePath, name);
        if (isMetadataExist(fullPath)) {
            throw new RuntimeException("元数据目录" + absolutePath + "已存在元数据" + name);
        }

        // 组装依赖
        buildMetadataRef(metadata);

        // 事件准备
        MetadataCreateEventBroker broker = SpringBeanUtils.getBean(MetadataCreateEventBroker.class);
        MetadataEventArgs args = new MetadataEventArgs();
        args.setMetadata(metadata);
        args.setPath(absolutePath);

        // 2. 保存前事件
        broker.fireMetadataCreatingEvent(args);

        RepositoryFactory.getInstance().getMetadataRepository().create(metadata, fullPath);

        // TODO创建后，需要清除元数据缓存
        // 4. 保存后事件
        broker.fireMetadataCreatedEvent(args);
    }

    public void saveMetadata(GspMetadata metadata, String path) {
        String dirPath = new File(path).getParent();

        // 设置上下文路径
        Utils.setMetadataPath(dirPath);

        // 1. 组装元数据依赖关系节点
        buildMetadataRef(metadata);

        // 事件准备
        MetadataEventBroker broker = SpringBeanUtils.getBean(MetadataEventBroker.class);
        MetadataEventArgs args = new MetadataEventArgs();
        args.setMetadata(metadata);
        args.setPath(dirPath);

        // 2. 保存前事件
        broker.fireMetadataSavingEvent(args);

        // 获取元数据的配置信息
        MetadataConfiguration metadataConfiguration = MetadataConfigurationHelper.getInstance().getMetadataConfigurationData(metadata.getHeader().getType());
        CommonConfigData commonData = metadataConfiguration.getCommon();
        // 资源元数据
        I18nCoreService i18nCoreService = new I18nCoreService();
        if (i18nCoreService.isI18nMetadata(metadata)) {
            GspMetadata resourceMetadata = i18nCoreService.extractResourceMetadata(metadata, path);
            i18nCoreService.extractLanguageMetadata(metadata, resourceMetadata, path);
            return;
        }

        // 普通元数据需要抽取资源元数据
        if (commonData.isCreatingResourceMetadata() && !i18nCoreService.isI18nMetadata(metadata)) {
            i18nCoreService.extractResourceMetadata(metadata, path);
        }

        // 3. 把元数据保存到文件
        RepositoryFactory.getInstance().getMetadataRepository().save(metadata, path);

        // 4. 保存后事件
        broker.fireMetadataSavedEvent(args);
    }

    public GspMetadata loadMetadata(String metadataFileName, String absolutePath) {
        String metadataPath = fileService.getCombinePath(absolutePath, metadataFileName);
        GspMetadata metadata = loadMetadata(metadataPath);
        return metadata;
    }

    public GspMetadata loadMetadata(String absolutePath) {
        GspMetadata metadata;
        if (!isMetadataExist(absolutePath)) {
            throw new RuntimeException(String.format("file not exist, filePath is %s", absolutePath));
        }
        try {
            RefCommonContext.setInvokeAtDesignTime(true);
            metadata = RepositoryFactory.getInstance().getMetadataRepository().load(absolutePath);
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            RefCommonContext.setInvokeAtDesignTime(false);
        }
        return metadata;
    }

    public GspMetadata loadMetadataByMetadataId(String metadataId, String absolutePath) {
        final List<GspMetadata> metadataList = getMetadataList(absolutePath);
        GspMetadata metadata = metadataList.stream().filter(md -> md.getHeader().getId().equals(metadataId)).findFirst().orElse(null);
        Utils.checkNPE(metadata, "工程" + absolutePath + "中找不到元数据" + metadataId);
        metadata = loadMetadata(metadata.getHeader().getFileName(), metadata.getRelativePath());
        return metadata;
    }

    public GspMetadata loadMetadataInBo(String absoluteMetadataPath, String absoluteProjPath) {
        absoluteProjPath = metadataProjectCoreService.getProjPath(absoluteProjPath);
        GspProject currentGspProjectInfo = gspProjectCoreService.getGspProjectInfo(absoluteProjPath);
        GspProject metadataGspProjectInfo = gspProjectCoreService.getGspProjectInfo(absoluteMetadataPath);
        if (!currentGspProjectInfo.getMetadataPackageName().equals(metadataGspProjectInfo.getMetadataPackageName())) {
            updateBoRef(metadataGspProjectInfo, absoluteMetadataPath, absoluteProjPath);
        }
        File file = new File(absoluteMetadataPath);
        return loadMetadata(file.getName(), file.getParent());
    }

    private void updateBoRef(GspProject gspProjInfo, String metadataFullPath, String currentProjPath) {
        String projectPath = Paths.get("..").resolve(gspProjInfo.getMetadataProjectName().toLowerCase()).toString();
        updateProjectReference(currentProjPath, gspProjInfo.getMetadataPackageName() + Utils.getMetadataPackageExtension(), projectPath);

        checkCircle(currentProjPath);
        MetadataProject metadataProject = metadataProjectCoreService.getMetadataProjInfo(metadataFullPath);
        MetadataProject currentMetadataProject = metadataProjectCoreService.getMetadataProjInfo(currentProjPath);
        metadataProjectCoreService.updateRefs(currentProjPath, currentMetadataProject, metadataProject.getMetadataPackageInfo());

        String[] projectNameSpace = gspProjInfo.getProjectNameSpace().split("\\.");
        String groupId;
        if (projectNameSpace.length == 1) {
            groupId = "com." + projectNameSpace[0].toLowerCase();
        } else {
            groupId = "com." + (projectNameSpace[0] + "." + projectNameSpace[1]).toLowerCase();
        }
        String artifactId = (gspProjInfo.getAppCode() + "-" + gspProjInfo.getServiceUnitCode() + "-" + gspProjInfo.getMetadataProjectName().replace("bo-", "") + "-api").toLowerCase();
        String packageVersion = "m0.1.0-SNAPSHOT";
        updateMavenReference(currentProjPath, groupId, artifactId, packageVersion);
    }

    private void updateMavenReference(String currentProjPath, String groupId, String artifactId,
        String packageVersion) {
        MavenPackageRefs mavenPackageRefs = new MavenPackageRefs();
        mavenPackageRefs.setGroupId(groupId);
        mavenPackageRefs.setArtifactId(artifactId);
        mavenPackageRefs.setVersion(packageVersion);
        MetadataProject metadataProject = metadataProjectCoreService.getMetadataProjInfo(currentProjPath);
        metadataProjectCoreService.updateMavenRefs(currentProjPath, metadataProject, mavenPackageRefs);
    }

    private void checkCircle(String currentProjPath) {
        List<String> chainOfRef = new ArrayList<>();
        GspProject gspProjectInfo = new GspProjectCoreService().getGspProjectInfo(currentProjPath);

        chainOfRef.add(gspProjectInfo.getMetadataProjectName().toLowerCase());
        try {
            getCircle(currentProjPath, chainOfRef);
        } catch (Exception e) {
            throw e;
        }
    }

    private void getCircle(String projectPath, List<String> chainOfRef) {
        MetadataProject metadataProject = metadataProjectCoreService.getMetadataProjInfo(projectPath);
        String curProjectName = metadataProject.getName().toLowerCase();
        if (metadataProject.getProjectRefs() != null && metadataProject.getProjectRefs().size() > 0) {
            metadataProject.getProjectRefs().forEach(projRef -> {
                String projectName = projRef.getProjectPath().replace("..\\", "").toLowerCase();
                String chain = chainOfRef.stream().filter(r -> r.endsWith(curProjectName) && Arrays.asList(r.split("->")).contains(projectName)).findFirst().orElse(null);
                if (chain != null) {
                    chain += "->" + projectName;
                    throw new RuntimeException("检测到循环引用：" + chain);
                }
                List<String> refs = chainOfRef.stream().filter(r -> r.endsWith(curProjectName)).collect(Collectors.toList());
                refs.forEach(r -> chainOfRef.add(r + "->" + projectName));
                List<String> refsToRemove = chainOfRef.stream().filter(r -> r.endsWith(curProjectName)).collect(Collectors.toList());
                refsToRemove.forEach(r -> chainOfRef.remove(r));

                String refProjectPath = Paths.get(metadataProjectCoreService.getProjPath(projectPath)).resolve(projRef.getProjectPath()).toString();
                getCircle(refProjectPath, chainOfRef);
            });
        }
    }

    private void updateProjectReference(String currentProjPath, String packageName, String packagePath) {
        ProjectHeader projectHeader = new ProjectHeader();
        projectHeader.setName(fileService.getFileNameWithoutExtension(packageName));
        projectHeader.setProjectPath(packagePath);
        MetadataProject metadataProject = metadataProjectCoreService.getMetadataProjInfo(currentProjPath);
        metadataProjectCoreService.updateProjectRefs(currentProjPath, metadataProject, projectHeader);
    }

    public GspMetadata getRefMetadata(String metadataID, String absolutePath) {
        if (absolutePath != null && !absolutePath.isEmpty()) {
            Utils.setMetadataPath(absolutePath);
        }
        RefCommonServiceImp refCommonService = new RefCommonServiceImp();
        return refCommonService.getRefMetadata(metadataID);
    }

    public GspMetadata getMetadataWithoutContent(String absolutePath) {
        return RepositoryFactory.getInstance().getMetadataRepository().getMetadataWithoutContent(absolutePath);
    }

    public void deleteMetadata(String absolutePath, String metadataFileName) {
        String fullPath = fileService.getCombinePath(absolutePath, metadataFileName);
        if (!isMetadataExist(fullPath)) {
            return;
        }
        // 如果不是元数据，则直接删除文件，如ts文件
        if (!isMetadata(fullPath)) {
            try {
                fileService.fileDelete(fullPath);
            } catch (IOException e) {
                e.printStackTrace();
            }
            return;
        }

        GspMetadata metadataWithoutContent = getMetadataWithoutContent(fullPath);

        // 事件准备
        MetadataEventBroker broker = SpringBeanUtils.getBean(MetadataEventBroker.class);
        MetadataEventArgs args = new MetadataEventArgs();
        args.setMetadata(metadataWithoutContent);
        args.setPath(fullPath);

        // 删除前事件
        broker.fireMetadataDeletingEvent(args);

        RepositoryFactory.getInstance().getMetadataRepository().delete(fullPath);

        broker.fireMetadataDeletedEvent(args);
    }

    public void deleteFolder(String absolutePath) {
        DirEventBroker broker = SpringBeanUtils.getBean(DirEventBroker.class);
        DirEventArgs args = new DirEventArgs();
        args.setPath(absolutePath);

        broker.fireDirDeletingEvent(args);

        try {
            fileService.deleteAllFilesUnderDirectory(absolutePath);
        } catch (IOException e) {
            e.printStackTrace();
        }

        broker.fireDirDeletedEvent(args);
    }

    public void renameMetadata(String oldFileName, String newFileName, String absolutePath) {
        if (oldFileName.equals(newFileName)) {
            return;
        }
        String oldFilePath = fileService.getCombinePath(absolutePath, oldFileName);
        if (!isMetadataExist(oldFilePath)) {
            throw new RuntimeException("元数据不存在：" + oldFilePath);
        }
        String newFilePath = fileService.getCombinePath(absolutePath, newFileName);
        if (!isMetadataExist(newFilePath)) {
            throw new RuntimeException("新元数据已存在：" + newFilePath);
        }

        validateMetadataCode(newFileName.substring(0, newFileName.lastIndexOf("\\.")), false);
        RepositoryFactory.getInstance().getMetadataRepository().rename(oldFilePath, newFilePath);

        // 修改文件内容，将 元数据头结点元数据名称一起修改
        GspMetadata metadata = loadMetadata(newFileName, absolutePath);
        metadata.getHeader().setName(newFileName.substring(0, newFileName.lastIndexOf("\\.")));
        RepositoryFactory.getInstance().getMetadataRepository().save(metadata, newFilePath);
    }

    private void validateMetadataCode(String code, boolean isLanguageMetadata) {
        if (code.length() > 255) {
            throw new RuntimeException("编号不可长于255个字符：" + code);
        }
        String rexStr = isLanguageMetadata ? "^[a-zA-Z_-\\x7f-\\xff][a-zA-Z0-9-._\\x7f-\\xff]*$" : "^[a-zA-Z_\\x7f-\\xff][a-zA-Z0-9._\\x7f-\\xff]*$";
        if (!Pattern.matches(rexStr, code)) {
            throw new RuntimeException("编号含有违法字符：" + code);
        }
    }

    public List<MetadataDto> getMetadataListInBo(String projPath, List<String> metadataTypes) {
        List<String> projectsInBo = metadataProjectCoreService.getProjectsInBo(projPath);

        // 生成型只能引用生成型，解析型可以引用生成型和解析型
        final MetadataProject metadataProjInfo = metadataProjectCoreService.getMetadataProjInfo(projPath);
        boolean isGenerationFlag = metadataProjInfo.getMetadataPackageInfo().getProcessMode() == null || metadataProjInfo.getMetadataPackageInfo().getProcessMode().equals(ProcessMode.GENERATION);

        if (isGenerationFlag) {
            projectsInBo = projectsInBo.stream().filter(project -> {
                MetadataProject metadataProjInfoInBo = metadataProjectCoreService.getMetadataProjInfo(project);
                return metadataProjInfoInBo.getMetadataPackageInfo().getProcessMode() == null || metadataProjInfoInBo.getMetadataPackageInfo().getProcessMode().equals(ProcessMode.GENERATION);
            }).collect(Collectors.toList());
        }

        // 获取列表，生成型只能引用生成型，解析型可以引用生成型和解析型
        List<MetadataDto> metadataList = new ArrayList<>();
        projectsInBo.forEach(project -> {
            MetadataProject metadataProjInfoInBo = metadataProjectCoreService.getMetadataProjInfo(project);
            if (isGenerationFlag) {
                boolean isEachProjectGenerationFlag = metadataProjInfoInBo.getMetadataPackageInfo().getProcessMode() == null || metadataProjInfoInBo.getMetadataPackageInfo().getProcessMode().equals(ProcessMode.GENERATION);
                if (!isEachProjectGenerationFlag) {
                    return;
                }
            }
            String metadataProjPath = project + File.separator + Utils.getMetadataProjPath();
            List<GspMetadata> result = getMetadataList(metadataProjPath, metadataTypes);
            for (GspMetadata metadata : result) {
                MetadataDto metadataDto = MetadataDtoConverter.asDto(metadata);
                metadataDto.setProjectName(new File(project).getName());
                metadataDto.setProcessMode(metadataProjInfoInBo.getMetadataPackageInfo().getProcessMode() == null ? ProcessMode.GENERATION.toString() : metadataProjInfoInBo.getMetadataPackageInfo().getProcessMode().toString());
                metadataList.add(metadataDto);
            }
        });
        return metadataList;
    }

    public List<GspMetadata> getMetadataList(String absolutePath, List<String> metadataTypes) {
        // 编译时缓存可用
        List<GspMetadata> metadataList = MetadataDevCacheManager.getMetadataListInProject(absolutePath);
        if (metadataList != null) {
            return metadataList;
        }
        metadataList = new ArrayList<>();
        List<String> paths = new ArrayList<>();
        //获取目录下的所有文件路径
        RepositoryFactory.getInstance().getMetadataRepository().getMetadatasUnderDir(paths, absolutePath);
        List<String> metadataAllTypes = Utils.getMetadataPostfixTypes();
        List<String> metadataTypeList = (metadataTypes == null || metadataTypes.size() == 0) ? metadataAllTypes : metadataTypes;
        for (String path : paths) {
            String extension = fileService.getExtension(path).toLowerCase();
            String result = metadataTypeList.stream().filter(item -> item.toLowerCase().equals(extension)).findAny().orElse(null);
            if (result != null) {
                GspMetadata metadataWithoutContent = getMetadataWithoutContent(path);
                if (metadataWithoutContent != null) {
                    metadataList.add(metadataWithoutContent);
                }
            }
        }
        return metadataList;
    }

    public List<MetadataType> getMetadataTypeList() {
        return MetadataTypeHelper.getInstance().getMetadataTypes();
    }

    public boolean isMetadataExist(String absolutePath) {
        return fileService.isFileExist(absolutePath);
    }

    public boolean isMetadataExistInProject(String projPath, String metadataID) {
        MetadataProject metadataProjInfo = metadataProjectCoreService.getMetadataProjInfo(projPath);
        if (Objects.isNull(metadataProjInfo)) {
            return false;
        }
        List<GspMetadata> metadataList = getMetadataList(metadataProjInfo.getProjectPath());
        return metadataList.stream().anyMatch(metadata -> metadata.getHeader().getId().equals(metadataID));
    }

    public String getRefPath(String absolutePath) {
        MetadataProject metadataProjInfo = metadataProjectCoreService.getMetadataProjInfo(absolutePath);
        return fileService.getCombinePath(metadataProjInfo.getProjectPath(), Utils.getMetadataBinPath());
    }

    public MetadataHeader getRefMetadataHeader(String metadataID, String absolutePath) {
        GspMetadata metadata = getRefMetadata(metadataID, absolutePath);
        Utils.checkNPE(metadata, "在工程" + absolutePath + "及其依赖中，无法找到元数据" + metadataID);
        return metadata.getHeader();
    }

    public List<MetadataHeader> getResourceMetadata(String metadataId, String proPath) {
        final List<GspMetadata> metadataList = getMetadataList(proPath);
        GspMetadata metadata = new GspMetadata();
        if (metadataList != null) {
            for (GspMetadata item : metadataList) {
                if (item.getHeader().getId().equals(metadataId)) {
                    metadata = item;
                    break;
                }
            }
        }
        List<MetadataHeader> metadataHeader = new ArrayList<>();
        if (metadata.getRefs() != null) {
            metadata.getRefs().forEach(item -> {
                if ("ResourceMetadata".equals(item.getDependentMetadata().getType())) {
                    metadataHeader.add(item.getDependentMetadata());
                }
            });
        }
        return metadataHeader;
    }

    public void setMetadataUri(String absolutePath) {
        Utils.setMetadataPath(absolutePath);
    }

    public GspMetadata getI18nMetadata(String fileName, String absolutePath, String language) {
        I18nCoreService i18nCoreService = new I18nCoreService();
        return i18nCoreService.getI18nMetadata(fileName, absolutePath, language);
    }

    public List<GspMetadata> getRefI18nMetadata(String resourceMdID, String resourceFileName, String path,
        String mavenPath, String packagePath) {
        RefI18nMetadataFactory refI18nMetadataFactory = new RefI18nMetadataFactory();
        IRefI18nFilter filter = refI18nMetadataFactory.createFilter(resourceMdID, path);
        return filter.getRefI18nMetadata(resourceMdID, resourceFileName, path, mavenPath, packagePath);
    }

    public List<GspMetadata> getMetadataList(String absolutePath) {
        //先从缓存获取
        String projPath = metadataProjectCoreService.getProjPath(absolutePath);
        if (StringUtils.isEmpty(projPath)) {
            return null;
        }
        String projectName = new File(projPath).getName();
        List<GspMetadata> metadataListCache = MetadataDevCacheManager.getMetadataListInProject(projectName);
        if (!CollectionUtils.isEmpty(metadataListCache)) {
            return metadataListCache;
        }
        List<GspMetadata> metadataList = new ArrayList<>();
        List<String> paths = new ArrayList<>();
        //获取目录下的所有文件路径
        RepositoryFactory.getInstance().getMetadataRepository().getMetadatasUnderDir(paths, absolutePath);
        List<String> metadataAllTypes = Utils.getMetadataPostfixTypes();
        for (String path : paths) {
            //获取文件后缀名
            String extension = fileService.getExtension(path).toLowerCase();
            boolean flag = false;
            for (String item : metadataAllTypes) {
                if (item.toLowerCase().equals(extension)) {
                    flag = true;
                    break;
                }
            }
            if (flag) {
                GspMetadata metadataWithoutContent = getMetadataWithoutContent(path);
                if (metadataWithoutContent != null) {
                    metadataList.add(metadataWithoutContent);
                }
            }
        }
//        if (!CollectionUtils.isEmpty(metadataList)) {
//            MetadataDevCacheManager.setMetadataListInProjectCache(projectName, metadataList);
//        }
        return metadataList;
    }

    public MetadataPackage getMetadataPackageInfo(String packageFileName, String packagePath) {
        String packageFullName = Utils.handlePackageName(packageFileName);

        String absolutePath = fileService.getCombinePath(packagePath, packageFullName);
        if (fileService.isFileExist(absolutePath)) {
            MetadataPackage metadataPackage = getMetadataPackage(packagePath, absolutePath);
            metadataPackage.getHeader().setLocation(Utils.handlePath(packagePath));
            return metadataPackage;
        } else {
            List<File> dirs = fileService.getDirectorys(packagePath);
            for (File dir : dirs) {
                String targetFile = fileService.getCombinePath(dir.getPath(), packageFullName);
                if (fileService.isFileExist(targetFile)) {
                    MetadataPackage metadataPackage = getMetadataPackage(packagePath, targetFile);
                    metadataPackage.getHeader().setLocation(Utils.handlePath(dir.getPath()));
                    return metadataPackage;
                }
            }
        }

        return null;
    }

    public List<GspMetadata> getMetadataListByRefedMetadataId(String path, String metadataId) {
        List<GspMetadata> metadataList = new ArrayList<>();
        List<String> projPaths = metadataProjectCoreService.getProjPathsInBoByRefedProjPath(path);
        projPaths.add(path);
        projPaths.forEach(projPath -> {
            List<GspMetadata> metadataListInProject = getMetadataList(projPath);
            metadataList.addAll(metadataListInProject.stream().filter(metadata -> {
                if (metadata.getRefs() == null) {
                    return false;
                }
                return metadata.getRefs().stream().anyMatch(ref -> ref.getDependentMetadata().getId().equals(metadataId));
            }).collect(Collectors.toList()));
        });
        return metadataList;
    }

    public boolean isMetadataRefed(String path) {
        if (!isMetadata(path)) {
            return false;
        }
        final GspMetadata metadataWithoutContent = getMetadataWithoutContent(path);
        final String projPath = metadataProjectCoreService.getProjPath(path);
        final Map<String, List<GspMetadata>> metadataHashMapByRefedMetadataId = getMetadataHashMapByRefedMetadataId(projPath, metadataWithoutContent.getHeader().getId());
        boolean isMetadataRefedFlag = metadataHashMapByRefedMetadataId != null && metadataHashMapByRefedMetadataId.size() > 0;
        if (isMetadataRefedFlag) {
            metadataHashMapByRefedMetadataId.forEach((projName, metadataList) -> {
                metadataList.forEach(metadata -> {
                    String log = "[LCM Warning]工程【" + projName + "】中的元数据【" + metadata.getHeader().getFileName() + "】依赖了此元数据";
                    LoggerDisruptorQueue.publishEvent(log, CAFContext.current.getUserId());
                });
            });
        }
        return isMetadataRefedFlag;
    }

    private boolean isMetadata(String path) {
        List<MetadataType> metadataTypeList = getMetadataTypeList();
        return metadataTypeList.stream().anyMatch(metadataType -> path.endsWith(metadataType.getPostfix()));
    }

    private Map<String, List<GspMetadata>> getMetadataHashMapByRefedMetadataId(String path, String metadataId) {
        Map<String, List<GspMetadata>> metadataHashMap = new HashMap<>();
        List<String> projPaths = metadataProjectCoreService.getProjPathsInBoByRefedProjPath(path);
        projPaths.add(path);
        projPaths.forEach(projPath -> {
            List<GspMetadata> metadataListInProject = getMetadataList(projPath);
            List<GspMetadata> metadataList = metadataListInProject.stream().filter(metadata -> {
                if (metadata.getRefs() == null) {
                    return false;
                }
                return metadata.getRefs().stream().anyMatch(ref -> ref.getDependentMetadata().getId().equals(metadataId));
            }).collect(Collectors.toList());
            if (metadataList != null && metadataList.size() > 0) {
                metadataHashMap.put(new File(projPath).getName(), metadataList);
            }
        });
        return metadataHashMap;
    }

    public Metadata4Ref getMetadataFromPackage(String packageName, String packagePath, String metadataId) {
        String packageFullName = Utils.handlePackageName(packageName);

        MetadataPackage packageInfo = getMetadataPackageInfo(packageFullName, packagePath);
        if (packageInfo == null) {
            return null;
        }
        GspMetadata metadata = null;
        String absolutePath = fileService.getCombinePath(packageInfo.getHeader().getLocation(), packageFullName);
        for (GspMetadata item : packageInfo.getMetadataList()) {
            if (item.getHeader().getId().equals(metadataId)) {

                lock.lock();
                try {
                    StringBuilder sb = new StringBuilder();
                    File file = new File(absolutePath);
                    ZipFile zf = new ZipFile(file);
                    InputStream in = new BufferedInputStream(new FileInputStream(absolutePath));
                    Charset utf8 = StandardCharsets.UTF_8;
                    ZipInputStream zin = new ZipInputStream(in, utf8);
                    ZipEntry ze;
                    while ((ze = zin.getNextEntry()) != null) {
                        BufferedReader br = new BufferedReader(
                            new InputStreamReader(zf.getInputStream(ze), utf8));
                        try {
                            if (fileService.getFileName(ze.toString()).equals(fileService.getFileName(item.getRelativePath()))) {
                                String line;
                                while ((line = br.readLine()) != null) {
                                    sb.append(line);
                                }
                            }
                        } catch (IOException e) {
//                                e.printStackTrace();
                            throw new IOException("读取元数据失败", e);
                        } finally {
                            br.close();
                        }
                    }
                    zin.closeEntry();
                    zin.close();
                    in.close();
                    zf.close();
                    metadata = new MetadataSerializer().deserialize(sb.toString(), GspMetadata.class);

                } catch (IOException | RuntimeException e) {
                    log.error("反序列化元数据失败,路径为：" + packagePath + "包名为：" + packageName, e);
//                        e.printStackTrace();
                    throw new RuntimeException("反序列化元数据失败,路径为：" + packagePath + "包名为：" + packageName, e);
                } finally {
                    lock.unlock();
//                    }
                }
            }
        }
        Metadata4Ref metadataDt = new Metadata4Ref();
        metadataDt.setPackageHeader(packageInfo.getHeader());
        metadataDt.setMetadata(metadata);

        return metadataDt;
    }

    public MetadataProject getMetadataProjInfo(String absolutePath) {
        String assemblyName = "";
        MetadataProject project;
        String projPath = MetadataProjectCoreService.getCurrent().getProjPath(absolutePath);
        String metadataPath = fileService.getCombinePath(projPath, Utils.getMetadataProjPath());
        if (fileService.isDirectoryExist(metadataPath)) {
            GspProject gspProject = new GspProjectCoreService().getGspProjectInfo(absolutePath);
            assemblyName = gspProject.getMetadataPackageName();
        }
        project = metadataProjectCoreService.getMetadataProjInfo(projPath);
        project.setCsprojAssemblyName(assemblyName);
        return project;
    }

    public List<MetadataIndexItemDto> getRemoteMetadataIndexList(String text, String path, String selectedPackageSource,
        List<String> typeList, boolean page, int pageSize, int pageIndex, boolean isFilterByRefs,
        boolean conflictAvoidFlag) {
        Utils.checkEmpty(path, "获取的路径为空：" + path);
        MetadataProject metadataProjInfo = getMetadataProjInfo(path);

        if (metadataProjInfo != null) {
            if (isFilterByRefs && (metadataProjInfo.getMavenPackageRefs() == null || metadataProjInfo.getMavenPackageRefs().size() == 0)) {
                return new ArrayList<>();
            }
        }

        try {
            String pageWebapiOfIndexServer = IndexServerManager.getInstance().getPageWebapiOfIndexServerWithProcessMode();
//            pageWebapiOfIndexServer = pageWebapiOfIndexServer.replace("10.24.15.33", "localhost");
            ProcessMode processMode = metadataProjInfo.getMetadataPackageInfo().getProcessMode() == null ? ProcessMode.GENERATION : metadataProjInfo.getMetadataPackageInfo().getProcessMode();
            MetadataInfoFilterWithProcessMode filter = getMetadataInfoFilter(text, typeList, page, pageSize, pageIndex, selectedPackageSource, path, isFilterByRefs, processMode);
            PageMetadataInfoWithProcessMode pageMetadataInfoWithProcessMode = RestTemplateService.instance.getObjectByPost(pageWebapiOfIndexServer, filter);
            List<MetadataInfoWithVersionWithProcessMode> metadataInfos = pageMetadataInfoWithProcessMode.getMetadataInfos();
            return buildIndexDtoFromMetadataInfoWithVersionWithProcessMode(metadataInfos);

        } catch (Exception e) {
            String pageWebapiOfIndexServer = IndexServerManager.getInstance().getPageWebapiOfIndexServer();
//            pageWebapiOfIndexServer = pageWebapiOfIndexServer.replace("10.24.15.33", "localhost");
            MetadataInfoFilter filter = getMetadataInfoFilter(text, typeList, page, pageSize, pageIndex, selectedPackageSource, path, isFilterByRefs);
            PageMetadataInfo pageMetadataInfo = RestTemplateService.instance.getObjectByPost(pageWebapiOfIndexServer, filter);
            List<MetadataInfoWithVersion> metadataInfos = pageMetadataInfo.getMetadataInfos();
            return buildIndexDtoFromMetadataInfoWithVersion(metadataInfos);
        }
    }

    public void throwMetadataNotFoundException(String metadataId) {
        final MetadataInfoWithVersion metadataInfoWithVersion = getIndexByMetadataId(metadataId);
        StringBuilder sb = new StringBuilder();
        sb.append("未找到元数据：");
        sb.append(metadataId);
        if (metadataInfoWithVersion != null) {
            sb.append("，元数据Code为：");
            sb.append(metadataInfoWithVersion.getMetadataCode());
            sb.append("，元数据包名为：");
            sb.append(metadataInfoWithVersion.getPackageCode()).append(Utils.getMetadataPackageExtension());
        }
        String msg = sb.toString();
        log.error(msg);
        throw new RuntimeException(msg);
    }

    private MetadataInfoWithVersion getIndexByMetadataId(String metadataId) {
        String metadataWebapiOfIndexServer = IndexServerManager.getInstance().getMetadataWebapiOfIndexServer() + "?metadataId=" + metadataId;
        List<MetadataInfoWithVersion> metadataInfoWithVersionList = RestTemplateService.instance.getObjectByGet(metadataWebapiOfIndexServer);
        if (metadataInfoWithVersionList != null && metadataInfoWithVersionList.size() > 0) {
            return metadataInfoWithVersionList.get(0);
        }
        return null;
    }

    public List<MetadataIndexItemDto> getLocalMetadataList(String text, String absolutePath, List<String> typeList,
        boolean page, int pageSize, int pageIndex, String packagePath) {
        List<MetadataIndexItemDto> mds = new ArrayList<>();
        // 根据索引，返回元数据dto列表
        List<LocalMetadataIndexItem> localMdIndexList = MetadataIndexCacheService.getInstance().getLocalPackagesMdIndexDic(packagePath);

        if (localMdIndexList == null || localMdIndexList.size() < 1) {
            return mds;
        }

        // 解析型
        final MetadataProject metadataProjInfo = getMetadataProjInfo(absolutePath);
        boolean isGenerationFlag = metadataProjInfo.getMetadataPackageInfo().getProcessMode() == null || metadataProjInfo.getMetadataPackageInfo().getProcessMode().equals(ProcessMode.GENERATION);

        if (isGenerationFlag) {
            localMdIndexList = localMdIndexList.stream().filter(localMetadataIndexItem -> localMetadataIndexItem.getProcessMode() == null || localMetadataIndexItem.getProcessMode().equals(ProcessMode.GENERATION.toString())).collect(Collectors.toList());
        }

        String packageNameExcluded = "";
        if (!(absolutePath == null || absolutePath.isEmpty())) {
            MetadataProject projInfo = metadataProjectCoreService.getMetadataProjInfo(absolutePath);
            if (projInfo != null) {
                packageNameExcluded = projInfo.getMetadataPackageInfo().getName();
            }
            if (!page) {
                for (LocalMetadataIndexItem localMdIndex : localMdIndexList) {
                    if (isPackMd(localMdIndex, typeList, text, packageNameExcluded)) {
                        MetadataIndexItemDto dto = assemblyMetadataIndexItemDto(localMdIndex);
                        mds.add(dto);
                    }
                }
            } else {
                int count = 0;
                int skip = pageIndex * pageSize;
                int max = pageSize + skip;
                for (LocalMetadataIndexItem localMdIndex : localMdIndexList) {
                    if (count >= max) {
                        break;
                    }
                    if (isPackMd(localMdIndex, typeList, text, packageNameExcluded)) {
                        count++;
                        if (count <= skip) {
                            continue;
                        }
                        MetadataIndexItemDto dto = assemblyMetadataIndexItemDto(localMdIndex);
                        mds.add(dto);
                    }
                }

            }
        }
        return mds;
    }

    public Metadata4RefDto pickMetadataIndex(int scopeType, String absolutePath,
        MetadataIndexItemDto metadataIndexItemDto, boolean isNeedMdDto, String packagePath, String mavenPath) {
        Metadata4Ref result;
        switch (scopeType) {
            case 1:
                result = pickLocalMdIndex(absolutePath, metadataIndexItemDto, isNeedMdDto, packagePath);
                break;
            // 远程maven中的元数据包
            case 2:
                result = pickRemoteMdIndex(absolutePath, metadataIndexItemDto, isNeedMdDto, packagePath, mavenPath);
                break;
            // 已引用的元数据包
            case 3:
                result = pickRefedMdIndex(absolutePath, metadataIndexItemDto, isNeedMdDto, packagePath, mavenPath);
                break;
            default:
                throw new IllegalArgumentException("Scope is invalid.");
        }
        if (result == null) {
            return null;
        }
        MetadataDto metadataDto = MetadataDtoConverter.asDto(result.getMetadata());
        Metadata4RefDto dto = new Metadata4RefDto();
        dto.setPackageHeader(result.getPackageHeader());
        dto.setMetadata(metadataDto);
        return dto;
    }

    public String getIndexServerStatus(String ip, String port) {
        final String testStatusWebapiIndexServer = IndexServerManager.getInstance().getTestStatusWebapiOfIndexServer(ip, port);
        return RestTemplateService.instance.getStatusByGet(testStatusWebapiIndexServer);
    }

    public void buildMetadataRef(GspMetadata metadata) {
        //TODO:考虑添加依赖关系是否变更标志，现在每次都需要获取依赖关系保存
        //构造元数据依赖关系
        IMetadataReferenceManager refManager = ReferenceManagerHelper.getInstance().getManager(metadata.getHeader().getType());
        if (refManager != null) {
            List<MetadataReference> refsCollection = refManager.getConstraint(metadata);
            metadata.setRefs(refsCollection);
        }
    }

    private Metadata4Ref pickRefedMdIndex(String currentPath, MetadataIndexItemDto metadataIndexItemDto,
        boolean isNeedMdDto, String packagePath, String mavenPath) {
        validateRemoteMdIndex(metadataIndexItemDto);
        MetadataProject metadataProject = getMetadataProjInfo(currentPath);
        Utils.checkNPE(metadataProject, "Path is invalid project folder:" + currentPath);

        String groupId = metadataIndexItemDto.getRepoPkg().get(0).getGroupId();
        String artifactId = metadataIndexItemDto.getRepoPkg().get(0).getArtifactId();
        String version = metadataIndexItemDto.getRepoPkg().get(0).getVersion();

        MavenPackageRefs ref = new MavenPackageRefs();
        ref.setGroupId(groupId);
        ref.setArtifactId(artifactId);
        ref.setVersion(version);
        boolean installFlag = packageCoreService.getInstallFlag(ref, false, mavenPath, packagePath);
        if (installFlag) {
            try {
                packageCoreService.installMdpkg(groupId, artifactId, version, currentPath, true, mavenPath, packagePath);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }

        Metadata4Ref metadata = null;
        if (isNeedMdDto) {
            String metadataPackagePath = fileService.getCombinePath(mavenPath, groupId + '-' + artifactId + '-' + version);
            metadata = getMetadataFromPackage(metadataIndexItemDto.getMdPkgName(), metadataPackagePath, metadataIndexItemDto.getId());
            Utils.checkNPE(metadata, metadataPackagePath + "中的原数据包" + metadataIndexItemDto.getMdPkgName() + "不包含此元数据：" + metadataIndexItemDto.getId());
        }

        return metadata;
    }

    private Metadata4Ref pickRemoteMdIndex(String currentPath, MetadataIndexItemDto metadataIndexItemDto,
        boolean isNeedMdDto, String packagePath, String mavenPath) {
        validateRemoteMdIndex(metadataIndexItemDto);
        MetadataProject metadataProject = getMetadataProjInfo(currentPath);
        Utils.checkNPE(metadataProject, "Path is invalid project folder:" + currentPath);

        String groupId = metadataIndexItemDto.getRepoPkg().get(0).getGroupId();
        String artifactId = metadataIndexItemDto.getRepoPkg().get(0).getArtifactId();
        String version = metadataIndexItemDto.getRepoPkg().get(0).getVersion();

        MavenPackageRefs ref = new MavenPackageRefs();
        ref.setGroupId(groupId);
        ref.setArtifactId(artifactId);
        ref.setVersion(version);

        // 安装的包是生成型的才需要安装jar
        boolean isGenerationFlag = metadataIndexItemDto.getProcessMode() == null || metadataIndexItemDto.getProcessMode().isEmpty() || metadataIndexItemDto.getProcessMode().equals(ProcessMode.GENERATION.toString());
        boolean installFlag = packageCoreService.getInstallFlag(ref, true, mavenPath, packagePath);
        if (installFlag) {
            try {
                packageCoreService.installMdpkg(groupId, artifactId, version, currentPath, isGenerationFlag, mavenPath, packagePath);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }

        Metadata4Ref metadata = null;
        if (isNeedMdDto) {
            String metadataPackagePath = fileService.getCombinePath(mavenPath, groupId + '-' + artifactId + '-' + version);
            metadata = getMetadataFromPackage(metadataIndexItemDto.getMdPkgName(), metadataPackagePath, metadataIndexItemDto.getId());
            Utils.checkNPE(metadata, metadataPackagePath + "中的原数据包" + metadataIndexItemDto.getMdPkgName() + "不包含此元数据：" + metadataIndexItemDto.getId());
        }

        MetadataPackageHeader metadataPackageHeader = new MetadataPackageHeader();
        metadataPackageHeader.setName(fileService.getFileNameWithoutExtension(metadataIndexItemDto.getMdPkgName()));
        metadataPackageHeader.setVersion(new MetadataPackageVersion("1.0.0"));
        ProcessMode processMode = isGenerationFlag ? ProcessMode.GENERATION : ProcessMode.INTERPRETATION;
        metadataPackageHeader.setProcessMode(processMode);
        metadataProjectCoreService.updateRefs(currentPath, metadataProject, metadataPackageHeader);
        metadataProjectCoreService.updateMavenRefs(currentPath, metadataProject, ref);

        return metadata;
    }

    private void validateRemoteMdIndex(MetadataIndexItemDto metadataIndexItemDto) {
        if (metadataIndexItemDto.getRepoPkg() == null || metadataIndexItemDto.getRepoPkg().size() < 1) {
            throw new IllegalArgumentException("未指定仓库包。");
        }
    }

    private Metadata4Ref pickLocalMdIndex(String currentPath, MetadataIndexItemDto metadataIndexItemDto,
        boolean isNeedMdDto, String packagePath) {
        String mdPkgName = metadataIndexItemDto.getMdPkgName();
        String mdPkgFullName = mdPkgName + Utils.getMetadataPackageExtension();
        // 获取工程信息
        MetadataProject metadataProject = getMetadataProjInfo(currentPath);
        Utils.checkNPE(metadataProject, "Path is invalid project folder:" + currentPath);
        // 本地是否存在
        if (!MetadataIndexCacheService.getInstance().isExistInLocalPackages(mdPkgName)) {
            throw new IllegalArgumentException("Local package: " + mdPkgName + " not exists");
        }

        Metadata4Ref metadata = null;
        if (isNeedMdDto) {
            String metadataPackagePath = fileService.getCombinePath(packagePath, mdPkgFullName);
            metadata = getMetadataFromPackage(mdPkgFullName, metadataPackagePath, metadataIndexItemDto.getId());
            Utils.checkNPE(metadata, metadataPackagePath + "中的元数据包" + metadataIndexItemDto.getMdPkgName() + "不包含此元数据：" + metadataIndexItemDto.getId());
        }

        MetadataPackageHeader metadataPackageHeader = new MetadataPackageHeader();
        metadataPackageHeader.setName(mdPkgName);
        metadataPackageHeader.setVersion(new MetadataPackageVersion("1.0.0"));
        metadataProjectCoreService.updateRefs(currentPath, metadataProject, metadataPackageHeader);

        return metadata;
    }

    private List<MetadataIndexItemDto> buildIndexDtoFromMetadataInfoWithVersion(
        List<MetadataInfoWithVersion> versions) {
        if (versions.size() < 1) {
            return new ArrayList<>();
        }
        List<MetadataIndexItemDto> dtos = new ArrayList<>();
        versions.forEach(version -> {
            MetadataIndexItemDto indexDto = new MetadataIndexItemDto();
            indexDto.setId(version.getMetadataId());
            indexDto.setCode(version.getMetadataCode());
            indexDto.setName(version.getMetadataName());
            indexDto.setNameSpace(version.getMetadataNamespace());
            indexDto.setType(version.getMetadataType());
            indexDto.setBizobjectID(version.getMdBizobjectId());
            indexDto.setLanguage(version.getMetadataLanguage());
            indexDto.setTranslating(version.getMetadataIsTranslating() != null && "true".equals(version.getMetadataIsTranslating()));
            indexDto.setMdPkgName(version.getPackageCode() + ".mdpkg");
            List<MetadataIndexRepoItemDto> metadataIndexRepoItemDtoList = new ArrayList<>();
            version.getMavenInfos().forEach(maveninfo -> {
                MetadataIndexRepoItemDto metadataIndexRepoItemDto = new MetadataIndexRepoItemDto();
                metadataIndexRepoItemDto.setGroupId(maveninfo.getMavenPackageGroupId());
                metadataIndexRepoItemDto.setArtifactId(maveninfo.getMavenPackageArtifactId());
                metadataIndexRepoItemDto.setVersion("m" + maveninfo.getMavenPackageVersion());
                metadataIndexRepoItemDto.setUrl(maveninfo.getMavenPackageUrl());
                metadataIndexRepoItemDto.setProcessMode(ProcessMode.GENERATION.toString());
                metadataIndexRepoItemDtoList.add(metadataIndexRepoItemDto);
            });
            if (version.getMavenInfos() == null || version.getMavenInfos().size() < 1) {
                indexDto.setRepoPkg(new ArrayList<>());
            } else {
                indexDto.setRepoPkg(metadataIndexRepoItemDtoList);
            }
            dtos.add(indexDto);
        });
        return dtos;
    }

    private List<MetadataIndexItemDto> buildIndexDtoFromMetadataInfoWithVersionWithProcessMode(
        List<MetadataInfoWithVersionWithProcessMode> versions) {
        if (versions.size() < 1) {
            return new ArrayList<>();
        }
        List<MetadataIndexItemDto> dtos = new ArrayList<>();
        versions.forEach(version -> {
            MetadataIndexItemDto indexDto = new MetadataIndexItemDto();
            indexDto.setId(version.getMetadataId());
            indexDto.setCode(version.getMetadataCode());
            indexDto.setName(version.getMetadataName());
            indexDto.setNameSpace(version.getMetadataNamespace());
            indexDto.setType(version.getMetadataType());
            indexDto.setBizobjectID(version.getMdBizobjectId());
            indexDto.setLanguage(version.getMetadataLanguage());
            indexDto.setTranslating(version.getMetadataIsTranslating() != null && "true".equals(version.getMetadataIsTranslating()));
            indexDto.setMdPkgName(version.getPackageCode() + ".mdpkg");
            indexDto.setProcessMode(version.getProcessMode());
            List<MetadataIndexRepoItemDto> metadataIndexRepoItemDtoList = new ArrayList<>();
            version.getMavenInfos().forEach(maveninfo -> {
                MetadataIndexRepoItemDto metadataIndexRepoItemDto = new MetadataIndexRepoItemDto();
                metadataIndexRepoItemDto.setGroupId(maveninfo.getMavenPackageGroupId());
                metadataIndexRepoItemDto.setArtifactId(maveninfo.getMavenPackageArtifactId());
                metadataIndexRepoItemDto.setVersion("m" + maveninfo.getMavenPackageVersion());
                metadataIndexRepoItemDto.setUrl(maveninfo.getMavenPackageUrl());
                metadataIndexRepoItemDto.setProcessMode(maveninfo.getProcessMode());
                metadataIndexRepoItemDtoList.add(metadataIndexRepoItemDto);
            });
            if (version.getMavenInfos() == null || version.getMavenInfos().size() < 1) {
                indexDto.setRepoPkg(new ArrayList<>());
            } else {
                indexDto.setRepoPkg(metadataIndexRepoItemDtoList);
            }
            dtos.add(indexDto);
        });
        return dtos;
    }

    private MetadataInfoFilter getMetadataInfoFilter(String text, List<String> typePostfixList, boolean page,
        int pageSize, int pageIndex, String selectedPackageSource, String projPath, boolean isFilterByRefs) {

        MetadataInfoFilter metadataInfoFilter = new MetadataInfoFilter();
        metadataInfoFilter.setCodeOrName(text);
        metadataInfoFilter.setPageable(page);
        metadataInfoFilter.setPageSize(pageSize);
        metadataInfoFilter.setPageIndex(pageIndex);
        // 检查类型是否正确
        List<String> metadataTypes = new ArrayList<>();
        if (typePostfixList != null && typePostfixList.size() > 0) {
            List<MetadataType> typeList = getMetadataTypeList();
            typeList.forEach(type -> {
                if (typePostfixList.contains(type.getPostfix().toLowerCase())) {
                    metadataTypes.add(type.getTypeCode().toLowerCase());
                }
            });
            metadataInfoFilter.setMetadataTypes(metadataTypes);
        }
        // packageSources
        List<String> packageSrouceList = new ArrayList<>();
        if (selectedPackageSource != null && !selectedPackageSource.isEmpty()) {
            MdpkgService mdpkgService = SpringBeanUtils.getBean(MdpkgService.class);
            List<PackageSourceDto> packageSourceDtoList = mdpkgService.getRepoList().getRepoList();
            if ("All".equals(selectedPackageSource)) {
                for (PackageSourceDto packageSourceDto : packageSourceDtoList) {
                    packageSrouceList.add(packageSourceDto.getSourceUrl());
                }
            } else {
                for (PackageSourceDto packageSourceDto : packageSourceDtoList) {
                    if (packageSourceDto.getId() != null) {
                        if (packageSourceDto.getId().equals(selectedPackageSource)) {
                            packageSrouceList.add(packageSourceDto.getSourceUrl());
                        }
                    }
                }
            }
            metadataInfoFilter.setPackageSources(getEntitySources(packageSrouceList));
        }

        // 获取自己的metadataCode
        MetadataProject projInfo = null;
        if (!(projPath == null || projPath.isEmpty())) {
            projInfo = getMetadataProjInfo(projPath);
            metadataInfoFilter.setPackageCodeExcluded(projInfo.getMetadataPackageInfo().getName());
        }

        // 获取MavenRefPackages
        List<MetadataMavenInfo> refsList = new ArrayList<>();
        if (projInfo != null && isFilterByRefs) {
            if (projInfo.getMavenPackageRefs() != null && projInfo.getMavenPackageRefs().size() > 0) {
                for (MavenPackageRefs ref : projInfo.getMavenPackageRefs()) {
                    MetadataMavenInfo packageRef = new MetadataMavenInfo();
                    packageRef.setMavenPackageGroupId(ref.getGroupId());
                    packageRef.setMavenPackageArtifactId(ref.getArtifactId());
                    packageRef.setMavenPackageVersion(ref.getVersion().substring(1));
                    refsList.add(packageRef);
                }
            }
        }
        metadataInfoFilter.setRefPackages(refsList);

        return metadataInfoFilter;
    }

    private MetadataInfoFilterWithProcessMode getMetadataInfoFilter(String text, List<String> typePostfixList,
        boolean page, int pageSize, int pageIndex, String selectedPackageSource, String projPath,
        boolean isFilterByRefs, ProcessMode processMode) {
        MetadataInfoFilterWithProcessMode metadataInfoFilterWithProcessMode = new MetadataInfoFilterWithProcessMode();
        metadataInfoFilterWithProcessMode.setCodeOrName(text);
        metadataInfoFilterWithProcessMode.setPageable(page);
        metadataInfoFilterWithProcessMode.setPageSize(pageSize);
        metadataInfoFilterWithProcessMode.setPageIndex(pageIndex);
        // 检查类型是否正确
        List<String> metadataTypes = new ArrayList<>();
        if (typePostfixList != null && typePostfixList.size() > 0) {
            List<MetadataType> typeList = getMetadataTypeList();
            typeList.forEach(type -> {
                if (typePostfixList.contains(type.getPostfix().toLowerCase())) {
                    metadataTypes.add(type.getTypeCode().toLowerCase());
                }
            });
            metadataInfoFilterWithProcessMode.setMetadataTypes(metadataTypes);
        }
        // packageSources
        List<String> packageSrouceList = new ArrayList<>();
        if (selectedPackageSource != null && !selectedPackageSource.isEmpty()) {
            MdpkgService mdpkgService = SpringBeanUtils.getBean(MdpkgService.class);
            List<PackageSourceDto> packageSourceDtoList = mdpkgService.getRepoList().getRepoList();
            if ("All".equals(selectedPackageSource)) {
                for (PackageSourceDto packageSourceDto : packageSourceDtoList) {
                    packageSrouceList.add(packageSourceDto.getSourceUrl());
                }
            } else {
                for (PackageSourceDto packageSourceDto : packageSourceDtoList) {
                    if (packageSourceDto.getId() != null) {
                        if (packageSourceDto.getId().equals(selectedPackageSource)) {
                            packageSrouceList.add(packageSourceDto.getSourceUrl());
                        }
                    }
                }
            }
            metadataInfoFilterWithProcessMode.setPackageSources(getEntitySources(packageSrouceList));
        }

        // 获取自己的metadataCode
        MetadataProject projInfo = null;
        if (!(projPath == null || projPath.isEmpty())) {
            projInfo = getMetadataProjInfo(projPath);
            metadataInfoFilterWithProcessMode.setPackageCodeExcluded(projInfo.getMetadataPackageInfo().getName());
        }

        // 获取MavenRefPackages
        List<MetadataMavenInfoWithProcessMode> refsList = new ArrayList<>();
        if (projInfo != null && isFilterByRefs) {
            if (projInfo.getMavenPackageRefs() != null && projInfo.getMavenPackageRefs().size() > 0) {
                for (MavenPackageRefs ref : projInfo.getMavenPackageRefs()) {
                    MetadataMavenInfoWithProcessMode packageRef = new MetadataMavenInfoWithProcessMode();
                    packageRef.setMavenPackageGroupId(ref.getGroupId());
                    packageRef.setMavenPackageArtifactId(ref.getArtifactId());
                    packageRef.setMavenPackageVersion(ref.getVersion().substring(1));
                    refsList.add(packageRef);
                }
            }
        }
        metadataInfoFilterWithProcessMode.setRefPackages(refsList);

        metadataInfoFilterWithProcessMode.setProcessMode(processMode.equals(ProcessMode.GENERATION) ? ProcessMode.GENERATION.toString() : "All");

        return metadataInfoFilterWithProcessMode;
    }

    private List<String> getEntitySources(List<String> packageSrouceList) {
        List<String> entitySources = new ArrayList<>();
        Map<String, List<String>> mavenSourceRule = MavenSourceRuleHelper.getInstance().getMavenSourceRuleMap();
        if (mavenSourceRule != null && mavenSourceRule.size() > 0) {
            for (String source : packageSrouceList) {
                String key = source.split("/")[source.split("/").length - 1];
                if (mavenSourceRule.containsKey(key)) {
                    entitySources.addAll(mavenSourceRule.get(key));
                } else {
                    entitySources.add(source);
                }
            }
        }
        return entitySources.stream().distinct().collect(Collectors.toList());
    }

    private boolean isPackMd(LocalMetadataIndexItem item, List<String> typeList, String text,
        String packageNameExcluded) {

        boolean isPack = false;
        if (typeList == null || typeList.contains(fileService.getExtension(item.getFileName().toLowerCase()))) {
            if (item.getMdPkgName().equals(packageNameExcluded)) {
                return false;
            }
            if (text == null || text.isEmpty()) {
                isPack = true;
            } else {
                if (isMath(item.getCode(), text)) {
                    isPack = true;
                } else if (isMath(item.getName(), text)) {
                    isPack = true;
                } else if (isMath(item.getMdPkgName(), text)) {
                    isPack = true;
                } else if (isMath(item.getNameSpace(), text)) {
                    isPack = true;
                }
            }
        }
        return isPack;
    }

    private boolean isMath(String a, String b) {
        if (a == null || a.isEmpty()) {
            return false;
        }
        return a.toLowerCase().contains(b.toLowerCase());
    }

    private MetadataIndexItemDto assemblyMetadataIndexItemDto(LocalMetadataIndexItem mdIndexDto) {
        MetadataIndexItemDto dto = new MetadataIndexItemDto();
        dto.setId(mdIndexDto.getId());
        dto.setName(mdIndexDto.getName());
        dto.setCode(mdIndexDto.getCode());
        dto.setFileName(mdIndexDto.getFileName());
        dto.setNameSpace(mdIndexDto.getNameSpace());
        dto.setMdPkgName(mdIndexDto.getMdPkgName());
        dto.setType(mdIndexDto.getType());
        dto.setRelativePath(mdIndexDto.getRelativePath());
        String processMode = mdIndexDto.getProcessMode() == null || mdIndexDto.getProcessMode().isEmpty() || mdIndexDto.getProcessMode().equals(ProcessMode.GENERATION.toString()) ? ProcessMode.GENERATION.toString() : ProcessMode.INTERPRETATION.toString();
        dto.setProcessMode(processMode);
        if (mdIndexDto.getRepoPkg() != null) {
            MetadataIndexRepoItemDto metadataIndexRepoItemDto = new MetadataIndexRepoItemDto();
            metadataIndexRepoItemDto.setGroupId(mdIndexDto.getRepoPkg().getGroupId());
            metadataIndexRepoItemDto.setArtifactId(mdIndexDto.getRepoPkg().getArtifactId());
            metadataIndexRepoItemDto.setVersion(mdIndexDto.getRepoPkg().getVersion());
            List<MetadataIndexRepoItemDto> list = new ArrayList<>();
            list.add(metadataIndexRepoItemDto);
            dto.setRepoPkg(list);
        }
        return dto;
    }

    private MetadataPackage getMetadataPackage(String defaultPackagePath, String absolutePath) {
        lock.lock();
        try {
            StringBuilder sb = new StringBuilder();
            File file = new File(absolutePath);
            ZipFile zf = new ZipFile(file);
            InputStream in = new BufferedInputStream(new FileInputStream(absolutePath));
            Charset utf8 = StandardCharsets.UTF_8;
            ZipInputStream zin = new ZipInputStream(in, utf8);
            ZipEntry ze;
            while ((ze = zin.getNextEntry()) != null) {
                try (BufferedReader br = new BufferedReader(
                    new InputStreamReader(zf.getInputStream(ze), utf8))) {
                    if (ze.toString().equals(Utils.getManifestFileName())) {
                        String line;
                        while ((line = br.readLine()) != null) {
                            sb.append(line);
                        }
                    }
                } catch (IOException e) {
                    throw new IOException("读取元数据失败", e);
                }
            }
            zin.closeEntry();
            zin.close();
            in.close();
            zf.close();
            ObjectMapper objectMapper = Utils.getMapper();
            return objectMapper.readValue(sb.toString(), MetadataPackage.class);
        } catch (IOException e) {
            throw new RuntimeException("反序列化元数据失败", e);
        } finally {
            lock.unlock();
        }
    }

    public boolean validateRepeatName(String absolutePath, String fileName) {
        String combinePath = fileService.getCombinePath(absolutePath, fileName);
        return !isMetadataExist(combinePath);
    }

    public List<GspMetadata> getMetadataByFilter(String absolutePath, MetadataFilter metadataFilter) {
        List<String> typeList = new ArrayList<>();
        if (metadataFilter.getMetadataPostfix() != null && !metadataFilter.getMetadataPostfix().isEmpty()) {
            String[] types = metadataFilter.getMetadataPostfix().split(",");
            typeList = Arrays.asList(types);
        }
        List<GspMetadata> metadataList = getMetadataList(absolutePath, typeList);
        // TODO 加上各元数据自己的过滤器
        return metadataList;
    }

    public void removeMetadataListCache(String absoluteProjPath) {
        MetadataProjectCoreService projectCoreService = new MetadataProjectCoreService();
        String projPath = projectCoreService.getProjPath(absoluteProjPath);
        if (!StringUtils.isEmpty(projPath)) {
            String projName = (new File(projPath)).getName();
            MetadataDevCacheManager.removeMetadataListInProject(projName);
        }
    }
}
